/**
 * let、const
 *  + 变量提升：var会产生变量提升效果，使用undefined初始化变量值，可以在声明前访问，在声明前访问输出undefined；let和const仅在自身作用域内提升，并且不会挂载到window上，但是会有TDZ暂时性死区，在声明前访问会报错，只能在声明之后访问
 *  + 作用域：由于var会产生变量提升，所以会有全局作用域；let和const的作用域仅限于自身声明的代码块内
 *  + 初始化：var和let都可以仅声明，不进行初始化值；const必须在声明的同时初始化值
 *  + 重新定义：var在第一次声明定义后，可以重新进行多次声明定义；let和const在同一作用域下只能被声明定义一次
 *  + 多次赋值：var和let可以进行多次赋值；const基础数据类型不能多次赋值，引用数据类型可以改变其内部的属性值
 */

/* 数组解构 */
const arr = [100, 200, 300]
const [foo, bar, baz] = arr
console.log(foo, bar, baz)

const [, , baz] = arr
console.log(baz)

const [foo, ...rest] = arr
console.log(rest)

const [foo, bar, baz, more] = arr
console.log(more) // undefined

const [foo, bar, baz = 123, more = 'default'] = arr
console.log(baz, more)

/* 对象解构 */
const obj = { name: 'zce', age: 18 }
const { name } = obj
console.log(name)

const age = 28
const { age: objAge } = obj
// const { age: objAge = 18 } = obj

/**
 * 模板字符串``
 *  + 支持直接换行操作
 *  + 支持变量，插值操作`${name} ${1 + 2}`
 *  + 标签函数
 */
// 标签函数
const name1 = 'tom'
const gender = false
function myTagFunc (strings, name, gender) {
  const sex = gender ? 'man' : 'woman'
  return strings[0] + name + strings[1] + sex + strings[2]
}
const r = myTagFunc`hey, ${name1} is a ${gender}`
console.log(r)

/* 字符串扩展方法 */
const msg = 'Error: foo is not defined.'
console.log(msg.startsWith('Error'))
console.log(msg.endsWith('.'))
console.log(msg.includes('foo'))

/* 参数默认值，剩余参数 */
// es5参数默认值
function foo1 (enable) {
  // enable = enable || true // 短路运算符，在传入false时会出问题，此时会变成true
  enable = enable === undefined ? true : enable // 三元运算替代短路运算
  console.log(enable)
}
// es6参数默认值
function foo2 (enable = true) {
  console.log(enable)
}
// es5剩余参数，arguments伪数组
function foo3 () {
  console.log(arguments)
}
// es6剩余参数，只能出现在型参最后一位，并只能使用一次
function foo4 (...args) {
  console.log(args)
}

/* 展开数组 */
const array = [1, 2, 3, 4, 5, 6]
console.log(...array)

/* 箭头函数this指向为外层this的指向 */
const obj = {
  name: '123',
  a () {
    console.log(this)
  },
  b: () => {
    console.log(this)
  },
  c () {
    setTimeout(() => {
      console.log(this)
      setTimeout(() => {
        console.log(this)
      }, 1000);
    }, 1000);
  },
  d: () => {
    setTimeout(() => {
      console.log(this)
    }, 1000);
  }
}

// obj.a()
// obj.b()
// obj.c()
// obj.d()

/* 对象字面量 */
const bar = '123'
const o = {
  foo: '123',
  bar, // 对象字面量
  method1 () {
    console.log(this)
  },
  [Math.random()]: '123' // 计算属性名
}
